/*
 * Copyright (C) 2014 Itai Hanski
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

package com.itaihanski.triangleview;

import com.itaihanski.triangleview.utils.LogUtil;

import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.render.Path;
import ohos.agp.utils.Color;
import ohos.agp.utils.Point;
import ohos.app.Context;

/**
 * The {@code TriangleView} allows for simple drawing of the triangle shape. The actual size and
 * shape if the triangle is determined by the size of this view. The direction and color can be set
 * in code using the public methods or via the XML attributes: {@code tr_direction} and
 * {@code tr_color}
 */
public class TriangleView extends Component implements Component.DrawTask {
    private static final String TAG = TriangleView.class.getSimpleName();
    private static final Direction DEFAULT_DIRECTION = Direction.UP;
    private static final int DEFAULT_COLOR = 0xff757575;
    private static final String ATTRIBUTE_DIRECTION = "tr_direction";
    private static final String ATTRIBUTE_COLOR = "tr_color";
    private static final long ALPHA_VALUE = 0x00000000ff000000;
    private static final int MAGIC_NUMBER_2 = 2;
    private static final int MAGIC_NUMBER_7 = 7;
    private static final int MAGIC_NUMBER_9 = 9;
    private static final int MAGIC_NUMBER_16 = 16;
    private static final String STRING_LEFT = "left";
    private static final String STRING_RIGHT = "right";
    private static final String STRING_UP = "up";

    private Paint mPaint;
    private Path mTrianglePath;
    private Direction mDirection = DEFAULT_DIRECTION;
    private int mColor = DEFAULT_COLOR;

    public TriangleView(Context context) {
        this(context, null);
    }

    public TriangleView(Context context, AttrSet attrs) {
        this(context, attrs, 0);
    }

    public TriangleView(Context context, AttrSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(attrs);
    }

    //
    // Initialization
    //
    private void init(AttrSet attrs) {
        if (attrs != null) {
            boolean isPresent = attrs.getAttr(ATTRIBUTE_DIRECTION).isPresent();
            if (isPresent) {
                mDirection = Direction.RIGHT;
                LogUtil.error(TAG, attrs.getAttr(ATTRIBUTE_DIRECTION).toString());
                String directionValue = attrs.getAttr(ATTRIBUTE_DIRECTION).get().getStringValue().trim();
                LogUtil.error(TAG, directionValue);

                if (STRING_LEFT.equalsIgnoreCase(directionValue)) {
                    mDirection = Direction.LEFT;
                } else if (STRING_RIGHT.equalsIgnoreCase(directionValue)) {
                    mDirection = Direction.RIGHT;
                } else if (STRING_UP.equalsIgnoreCase(directionValue)) {
                    mDirection = Direction.UP;
                } else {
                    mDirection = Direction.DOWN;
                }
            }

            isPresent = attrs.getAttr(ATTRIBUTE_COLOR).isPresent();
            if (isPresent) {
                String colorValue = attrs.getAttr(ATTRIBUTE_COLOR).get().getStringValue().trim();
                LogUtil.error(TAG, colorValue);
                mColor = parseColor(colorValue);
            }
        } else {
            mDirection = DEFAULT_DIRECTION;
            mColor = DEFAULT_COLOR;
        }

        mPaint = new Paint();
        mPaint.setStyle(Paint.Style.FILL_STYLE);
        mPaint.setColor(new Color(mColor));
        mPaint.setAntiAlias(true);
        addDrawTask(this);
    }

    private int parseColor(String colorString) {
        if (colorString != null && colorString.charAt(0) == '#') {
            long color = Long.parseLong(colorString.substring(1), MAGIC_NUMBER_16);
            if (colorString.length() == MAGIC_NUMBER_7) {
                // Set the alpha value
                color |= ALPHA_VALUE;
            } else if (colorString.length() != MAGIC_NUMBER_9) {
                LogUtil.error(TAG, "IllegalArgument Unknown color");
            } else {
                LogUtil.error(TAG, "Nothing");
            }
            return (int) color;
        } else {
            return DEFAULT_COLOR;
        }
    }

    //
    // Public API
    //

    /**
     * Set the color of the triangle.
     *
     * @param color the color of the triangle.
     */
    public void setColor(int color) {
        if (mColor != color) {
            mColor = color;
            if (mPaint != null) {
                mPaint.setColor(new Color(color));
            }
            mTrianglePath = null;
            invalidate();
        }
    }

    /**
     * Set the direction of the triangle.
     *
     * @param direction the direction of the triangle.
     */
    public void setDirection(Direction direction) {
        if (direction != mDirection) {
            mDirection = direction;
            mTrianglePath = null;
        }
        invalidate();
    }

    //
    // View Overrides
    //
    @Override
    public void onDraw(Component component, Canvas canvas) {
        canvas.drawPath(getTrianglePath(), mPaint);
        invalidate();
    }

    //
    // Utility Methods
    //
    private Path getTrianglePath() {
        if (mTrianglePath == null) {
            mTrianglePath = new Path();
            int width = getWidth();
            int height = getHeight();
            Point p1;
            Point p2;
            Point p3;
            switch (mDirection) {
                case LEFT:
                    p1 = new Point(width, 0);
                    p2 = new Point(width, height);
                    p3 = new Point(0, height / MAGIC_NUMBER_2);
                    break;
                case UP:
                    p1 = new Point(0, height);
                    p2 = new Point(width, height);
                    p3 = new Point(width / MAGIC_NUMBER_2, 0);
                    break;
                case RIGHT:
                    p1 = new Point(0, 0);
                    p2 = new Point(0, height);
                    p3 = new Point(width, height / MAGIC_NUMBER_2);
                    break;
                case DOWN:
                default:
                    p1 = new Point(0, 0);
                    p2 = new Point(width, 0);
                    p3 = new Point(width / MAGIC_NUMBER_2, height);
            }
            mTrianglePath.moveTo(p1.position[0], p1.position[1]);
            mTrianglePath.lineTo(p2.position[0], p2.position[1]);
            mTrianglePath.lineTo(p3.position[0], p3.position[1]);
        }
        return mTrianglePath;
    }

    /**
     * Direction of the triangle pointed side to be drawn on
     */
    public enum Direction {
        /**
         * Left direction
         */
        LEFT,
        /**
         * Up direction
         */
        UP,
        /**
         * Right direction
         */
        RIGHT,
        /**
         * Down direction
         */
        DOWN
    }
}
